/*
 * 人员部件索引 - 人员部件数据索引定义
 * 
 * 主要功能：
 * - 定义人员部件数据的索引结构
 * - 提供人员数据的数据库索引支持
 * - 实现人员数据的快速查询
 * - 支持GraphQL过滤功能
 */

using Lombiq.TrainingDemo.Models;
using OrchardCore.ContentManagement;
using System;
using YesSql.Indexes;

namespace Lombiq.TrainingDemo.Indexes;

/// <summary>
/// 人员部件索引 - 定义人员部件数据的索引结构
/// 
/// 主要用途：
/// - 定义人员部件数据的索引结构
 //* - 提供人员数据的数据库索引支持
 //* - 实现人员数据的快速查询
 //* - 支持GraphQL过滤功能
 //* 
 //* 使用场景：
/// - 为人员数据提供数据库索引
/// - 支持按出生日期和惯用手进行查询
/// - 实现GraphQL的数据库端过滤
/// - 提供高效的人员数据检索
/// 
/// 设计原因：
/// - 为人员数据提供高效的查询支持
/// - 实现数据库级别的索引优化
/// - 支持GraphQL的复杂过滤需求
/// - 提供可扩展的索引结构
/// 
/// 设计模式：
/// - 索引模式：继承MapIndex实现数据库索引
/// - 映射模式：使用IndexProvider实现数据映射
/// - 条件模式：使用When方法实现条件索引
/// - 提供程序模式：实现IndexProvider接口
/// </summary>
// 这也与我们之前在BookIndex.cs中看到的非常相似。区别在于我们现在有ContentItems而不是简单对象。
public class PersonPartIndex : MapIndex
{
    /// <summary>
    /// 内容项ID - 引用内容项的ID
    /// </summary>
    public string ContentItemId { get; set; }

    /// <summary>
    /// 出生日期 - 仅用于演示目的，以便我们可以对其运行查询
    /// </summary>
    public DateTime? BirthDateUtc { get; set; }

    /// <summary>
    /// 惯用手 - 仅用于演示目的，以便我们可以在GraphQL中展示枚举过滤
    /// </summary>
    public Handedness Handedness { get; set; }
}

/// <summary>
/// 人员部件索引提供程序 - 为ContentItem提供PersonPartIndex的映射
/// 
/// 主要用途：
/// - 为ContentItem提供PersonPartIndex的映射
 //* - 实现内容项到索引记录的自动映射
 //* - 支持条件索引（仅对有PersonPart的内容项建立索引）
 //* - 提供GraphQL过滤的数据库支持
 //* 
 //* 使用场景：
/// - 为具有PersonPart的内容项自动创建索引
/// - 支持按出生日期和惯用手进行GraphQL过滤
/// - 实现高效的数据库查询
/// - 提供条件索引的示例
/// 
/// 设计原因：
/// - 为内容项提供高效的索引支持
/// - 实现条件索引以减少不必要的索引记录
/// - 支持GraphQL的数据库端过滤
/// - 提供灵活的索引策略
/// 
/// 设计模式：
/// - 提供程序模式：继承IndexProvider<T>实现索引提供
/// - 条件模式：使用When方法实现条件索引
/// - 映射模式：使用Map方法实现数据映射
/// - 内容模式：处理ContentItem的特殊需求
/// </summary>
// 不要忘记在服务提供程序中注册此类（请参阅：Startup.cs）。
public class PersonPartIndexProvider : IndexProvider<ContentItem>
{
    /// <summary>
    /// 描述方法 - 定义ContentItem到PersonPartIndex的映射
    /// 
    /// 功能说明：
    /// - 为具有PersonPart的内容项创建索引记录
    /// - 使用条件索引避免不必要的索引记录
    /// - 映射人员部件的关键属性到索引
    /// - 支持GraphQL的数据库端过滤
    /// 
    /// 索引策略：
    /// - 仅对具有PersonPart的内容项建立索引
    /// - 可以扩展为仅对已发布项目建立索引
    /// - 可以扩展为仅对最新版本建立索引
    /// - 避免在索引表中填充不必要的行有助于性能
    /// 
    /// 映射字段：
    /// - ContentItemId：内容项ID
    /// - BirthDateUtc：出生日期
    /// - Handedness：惯用手
    /// </summary>
    /// <param name="context">描述上下文</param>
    public override void Describe(DescribeContext<ContentItem> context) =>
        context.For<PersonPartIndex>()
            // 注意，我们可以在这里编写任何逻辑来确定何时应该为内容项创建索引记录。
            // 这里我们将为每个具有PersonPart的内容项创建一个记录。但是，我们可以例如
            // 只为已发布项目建立索引（如果您不想查询草稿；您可以检查contentItem.Published），
            // 或者只对最新版本建立索引（无论它是草稿还是已发布版本，contentItem.Latest显示这个）。
            // 避免在索引表中填充不必要的行有助于性能，并使数据库管理整体更容易。
            .When(contentItem => contentItem.Has<PersonPart>())
            // 注意，索引提供程序比Map()和When()（尽管这些是您最需要使用的）有更多内容，
            // 请参阅YesSQL文档：https://github.com/sebastienros/yessql/wiki/Tutorial
            .Map(contentItem =>
            {
                var personPart = contentItem.As<PersonPart>();

                return new PersonPartIndex
                {
                    ContentItemId = contentItem.ContentItemId,
                    BirthDateUtc = personPart.BirthDateUtc,
                    Handedness = personPart.Handedness,
                };
            });
}

// 训练部分结束：内容项和内容部件开发

// 下一站：Controllers/PersonListController
